/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 - 2008 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.web.gwt.form.client.widget.item.impl;

import java.util.ArrayList;
import java.util.List;

import com.genia.toolbox.web.gwt.basics.client.GwtHelper;
import com.genia.toolbox.web.gwt.basics.client.oracle.SelectSuggestBox;
import com.genia.toolbox.web.gwt.basics.client.widget.HyperLinkButton;
import com.genia.toolbox.web.gwt.basics.client.widget.WidgetFactory;
import com.genia.toolbox.web.gwt.form.client.CssNames;
import com.genia.toolbox.web.gwt.form.client.form.SubFormMultipleItem;
import com.genia.toolbox.web.gwt.form.client.manager.FormManager;
import com.genia.toolbox.web.gwt.form.client.message.Messages;
import com.genia.toolbox.web.gwt.form.client.oracle.FormServiceSuggestOracle;
import com.genia.toolbox.web.gwt.form.client.process.ProcessSortable;
import com.genia.toolbox.web.gwt.form.client.widget.SortableWidget;
import com.genia.toolbox.web.gwt.form.client.widget.item.ItemWidgetModifyListener;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * This class is the widget representing a {@link SubFormMultipleItem}.
 */
public class SubFormMultipleItemWidget
    extends AbstractSimpleItemWidget<SubFormMultipleItem>
    implements SortableWidget
{
  /**
   * the manager handling the current form.
   */
  private final transient FormManager formManager;

  /**
   * the registered {@link ItemWidgetModifyListener}.
   */
  private final transient ItemWidgetModifyListenerCollection modifyListeners = new ItemWidgetModifyListenerCollection();

  /**
   * the {@link FormServiceSuggestOracle} that allows to choose values for this
   * item.
   */
  private final transient FormServiceSuggestOracle oracle;

  /**
   * wether not to send notification of changes.
   */
  private transient boolean stopNotification = false;

  /**
   * the textbox allowing the user to type.
   */
  private final transient SelectSuggestBox suggestBox;

  /**
   * a <code>List</code> of <code>String</code> representing the values of this
   * widget.
   */
  private transient List<String> values = new ArrayList<String>();

  /**
   * the Panel containing the selected values.
   */
  private final transient VerticalPanel valuesPanel;

  /**
   * the Panel containing all the sub-widgets.
   */
  private final transient VerticalPanel vPanel = new VerticalPanel();

  /**
   * the widgets that the setErrorMessage must modify.
   */
  private final transient Widget[] widgetsToToggle;



  /**
   * constructor.
   * 
   * @param formManager
   *          the manager handling the current form
   * @param item
   *          the item begin rendered
   */
  public SubFormMultipleItemWidget(final FormManager formManager, final SubFormMultipleItem item)
  {
    super(item);
    this.formManager = formManager;

    // The oracle
    oracle = new FormServiceSuggestOracle();
    oracle.setFieldName(item.getName());
    oracle.setFormIdentifier(formManager.getFormIdentifier());
    oracle.setDataIdentifier(formManager.getDataIdentifier());
    oracle.setDisplayStringHTML(item.isDisplayStringHTML());

    // The panel containing the input text.
    HorizontalPanel hPanel = new HorizontalPanel();

    // The label
    Label label = new Label();
    GwtHelper.fillText(label, item.getLabelKey());
    hPanel.add(label);

    if (item.isEnabled()) {
      // the input text

      suggestBox = new SelectSuggestBox(oracle);

      suggestBox.addChangeListener(new ChangeListener()
      {

        public void onChange(Widget widget)
        {
          if (suggestBox.getValue() != null) {
            addValue(suggestBox.getValue());
            suggestBox.setValue(null);
          }
        }

      });

      hPanel.add(suggestBox);
      // the new button
      if (item.getSubFormPolicy().isCanCreate() || item.getSubFormPolicy().isShowDisabled()) {
        final HyperLinkButton newButton = WidgetFactory.newHyperLinkButton(Messages.NEW_BUTTON_MESSAGE, CssNames.NEW_BUTTON_CSS_STYLE);
        newButton.setEnabled(item.getSubFormPolicy().isCanCreate());
        if (item.getSubFormPolicy().isCanCreate()) {
          newButton.addClickListener(new ClickListener()
          {

            public void onClick(final Widget widget)
            {
              SubFormHelper.startNewForm(SubFormMultipleItemWidget.this, formManager, null, true);
            }

          });
        }
        hPanel.add(newButton);
      }
      widgetsToToggle = new Widget[] { vPanel, suggestBox };
    }
    else {
      suggestBox = null;
      widgetsToToggle = new Widget[] { vPanel };
    }

    vPanel.addStyleName(CssNames.SUB_FORM_MULTIPLE_ITEM_CSS_STYLE);
    vPanel.addStyleName(item.getName());

    vPanel.add(hPanel);

    valuesPanel = ProcessSortable.getVerticalPanel(this);
    valuesPanel.addStyleName(CssNames.SUB_FORM_MULTIPLE_ITEM_VALUES_PANEL_CSS_STYLE);
    vPanel.add(valuesPanel);

    initWidget(vPanel);
  }



  /**
   * add a listener that is called each time the value of this object change.
   * 
   * @param modifyListener
   *          the callback
   */
  public void addModifyListener(final ItemWidgetModifyListener modifyListener)
  {
    modifyListeners.add(modifyListener);
  }



  /**
   * Add a new value to this widget.
   * 
   * @param value
   *          the value to add
   */
  private void addValue(final String value)
  {
    if (values.contains(value)) {
      return;
    }

    final HorizontalPanel hPanel = new HorizontalPanel();

    // Label
    Label label = new Label();
    oracle.requestText(value, label);
    hPanel.add(label);

    if (getItem().isEnabled()) {

      // Remove button
      final HyperLinkButton removeButton = WidgetFactory.newHyperLinkButton(Messages.REMOVE_BUTTON_MESSAGE, CssNames.REMOVE_BUTTON_CSS_STYLE);
      removeButton.addClickListener(new ClickListener()
      {

        public void onClick(Widget widget)
        {
          values.remove(value);
          valuesPanel.remove(hPanel);
          modifyListeners.onModify(SubFormMultipleItemWidget.this);
        }
      });
      hPanel.add(removeButton);

      // Update button
      final SubFormMultipleItem item = getItem();
      if (item.getSubFormPolicy().isCanUpdate() || item.getSubFormPolicy().isShowDisabled()) {
        final HyperLinkButton updateButton = WidgetFactory.newHyperLinkButton(Messages.UPDATE_BUTTON_MESSAGE, CssNames.UPDATE_BUTTON_CSS_STYLE);
        updateButton.setEnabled(item.getSubFormPolicy().isCanCreate());
        if (item.getSubFormPolicy().isCanCreate()) {
          updateButton.addClickListener(new ClickListener()
          {

            public void onClick(final Widget widget)
            {
              SubFormHelper.startNewForm(SubFormMultipleItemWidget.this, formManager, value, true);
            }

          });
        }
        hPanel.add(updateButton);
      }
    }

    // Add the new value.
    valuesPanel.add(hPanel);
    values.add(value);
    if (!stopNotification) {
      modifyListeners.onModify(this);
    }
  }



  /**
   * returns the current values of this item.
   * 
   * @return a <code>List</code> of <code>String</code> representing the current
   *         values of this item
   */
  public List<String> getValues()
  {
    return values;
  }



  /**
   * returns an array containing all the widgets that the setErrorMessage must
   * modify.
   * 
   * @return an array containing all the widgets that the setErrorMessage must
   *         modify
   */
  @Override
  protected Widget[] getWidgetsToToggle()
  {
    return widgetsToToggle;
  }



  /**
   * move the given value to the given position.
   * 
   * @param oldIndex
   *          the index of the value to move
   * @param newIndex
   *          the index of the final destination of the value
   * @see com.genia.toolbox.web.gwt.form.client.widget.SortableWidget#moveValue(int,
   *      int)
   */
  public void moveValue(int oldIndex, int newIndex)
  {
    ProcessSortable.move(values, oldIndex, newIndex);
    modifyListeners.onModify(this);
  }



  /**
   * set the current values of this item.
   * 
   * @param values
   *          a <code>List</code> of <code>String</code> representing the new
   *          values of this item
   */
  public void setValues(List<String> values)
  {
    this.values = new ArrayList<String>();
    valuesPanel.clear();
    if (values != null) {
      stopNotification = true;
      for (final String value : values) {
        addValue(value);
      }
    }
    stopNotification = false;
    modifyListeners.onModify(this);
  }
}
